梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
动态规划的本质:它是一种 “以空间换时间”的优化算法,核心是把复杂问题拆解为多个重叠的子问题,通过记录子问题的最优解(状态),避免重复计算,最终由子问题的最优解推导出原问题的最优解。
树形动态规划是解决树结构上的最优解问题,比如 “树的最大路径和”“打家劫舍 III(树形)”。这类问题的特点是问题定义在树上,子问题对应树的子树,状态转移依赖于节点的子节点状态,解题时通常采用后序遍历(先求解子树,再求解当前节点)。
问题描述:
算法解析:
#include <iostream>
#include <vector>
#include <unordered_map>
#include"LinkedBSTree.h"
using namespace std;
int max_diameter; // 全局最优解(直径)
unordered_map<BSTNode<int>*, int> dp; // 显式存储dp[root]:key=节点,value=向下最长路径长度
// 计算dp[root],并更新全局直径
int calculateDP(BSTNode<int>* root) {
// 边界条件:空节点,dp值为0
if (root == nullptr) {
dp[root] = 0;
return 0;
}
// 记忆化:如果已经计算过当前节点的dp值,直接返回(避免重复计算)
if (dp.find(root) != dp.end()) {
return dp[root];
}
// 状态转移:计算左右子节点的dp值(子问题)
int left_dp = calculateDP(root->left); // dp[left]
int right_dp = calculateDP(root->right); // dp[right]
// 更新全局最优解:当前节点作为拐点的路径长度 = dp[left] + dp[right]
max_diameter = max(max_diameter, left_dp + right_dp);
// 计算当前节点的dp值,并存储(记忆化)
dp[root] = max(left_dp, right_dp) + 1;
return dp[root];
}
int main() {
LinkedBSTree<int> tree;
tree.insertNode(3);
tree.insertNode(1);
tree.insertNode(4);
tree.insertNode(2);
tree.insertNode(5);
//tree.levelOrder();
BSTNode<int>* root = tree.getRoot();
calculateDP(root);
cout << max_diameter ;
return 0;
}
4
问题描述:
算法解析:
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits> // 用于INT_MIN
#include"LinkedBSTree.h"
using namespace std;
int max_sum; // 全局最大路径和
// 递归函数:返回以root为起点向下延伸的最大路径和(局部状态dp[root])
int maxPathSum(BSTNode<int>* root) {
if (root == nullptr) {
return 0; // 空节点的局部路径和为0(无贡献)
}
// 计算左右子树的局部路径和(如果为负则取0,即不选该子树)
int left_dp = max(maxPathSum(root->left), 0);
int right_dp = max(maxPathSum(root->right), 0);
// 更新全局最大路径和:当前节点作为拐点的路径和 = 根值 + 左局部 + 右局部
max_sum = max(max_sum, root->data + left_dp + right_dp);
// 返回当前节点的局部路径和:根值 + 左右局部的最大值(只能选一个方向延伸)
return root->data + max(left_dp, right_dp);
}
int main() {
max_sum = INT_MIN; // 初始化为最小整数(应对全负数的情况)
LinkedBSTree<int> tree;
tree.insertNode(2);
tree.insertNode(1);
tree.insertNode(3);
//tree.levelOrder();
BSTNode<int>* root = tree.getRoot();
maxPathSum(root);
cout << max_sum ;
return 0;
}
6
问题描述:
算法解析:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 递归函数:返回当前节点的dp数组({不选当前节点的最大值,选当前节点的最大值})
pair<int, int> rob(BSTNode<int>* root) {
// 边界条件:空节点,两种状态都是0
if (root == nullptr) {
return {0, 0};
}
// 递归计算左右子节点的dp状态(后序遍历,先子后父)
auto [left_not, left_choose] = rob(root->left);
auto [right_not, right_choose] = rob(root->right);
// 状态转移1:选当前节点 → 左右子节点都不能选
int choose = root->data + left_not + right_not;
// 状态转移2:不选当前节点 → 左右子节点可选可不选,取最大值相加
int not_choose = max(left_not, left_choose) + max(right_not, right_choose);
// 返回当前节点的两种状态
return {not_choose, choose};
}
int main() {
LinkedBSTree<int> tree;
tree.insertNode(5);
tree.insertNode(3);
tree.insertNode(6);
tree.insertNode(4);
tree.insertNode(7);
//tree.levelOrder();
BSTNode<int>* root = tree.getRoot();
auto [not_choose_root, choose_root] = rob(root);
cout << max(not_choose_root, choose_root) ;
return 0;
}
16